package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"time"

	"gopkg.in/ini.v1"
)

var Logger *log.Logger
var ListenPort int
var ZlmScheme string
var ZlmIP string
var ZlmPort int
var ZlmSecret string
var ZlmVhost string

func initConfig() {
	cfg, err := ini.Load("./config/config.ini")
	ListenPort, _ = cfg.Section("server").Key("port").Int()
	Logger.Println("ListenPort:", ListenPort)
	ZlmScheme = cfg.Section("zlm").Key("scheme").String()
	Logger.Println("ZlmScheme:", ZlmScheme)
	ZlmIP = cfg.Section("zlm").Key("ip").String()
	Logger.Println("ZlmIP:", ZlmIP)
	ZlmPort, _ = cfg.Section("zlm").Key("port").Int()
	Logger.Println("ZlmPort:", ZlmPort)
	ZlmSecret = cfg.Section("zlm").Key("secret").String()
	Logger.Println("ZlmSecret:", ZlmSecret)
	ZlmVhost = cfg.Section("zlm").Key("vhost").String()
	Logger.Println("ZlmVhost:", ZlmVhost)
	if err != nil {
		log.Fatalf(" SON marshaling failed: %s", err)
	}
}

func logTofile(logPath string, logPrefix string, logFlags int) *log.Logger {
	var ret *log.Logger
	logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
	if err != nil {
		ret = log.New(logFile, logPrefix, logFlags)
	} else {
		ret = log.New(os.Stdout, logPrefix, logFlags)
	}
	return ret
}

// 发送GET请求
// url：         请求地址
// response：    请求返回的内容
func Get(url string) string {

	// 超时时间：5秒
	client := &http.Client{Timeout: 5 * time.Second}
	resp, err := client.Get(url)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	var buffer [512]byte
	result := bytes.NewBuffer(nil)
	for {
		n, err := resp.Body.Read(buffer[0:])
		result.Write(buffer[0:n])
		if err != nil && err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}
	}

	return result.String()
}

type StreamInfo struct {
	App              string `json:"app"`
	Stream           string `json:"stream"`
	Schema           string `json:"schema"`
	BytesSpeed       int    `json:"bytesSpeed"`
	ReaderCount      int    `json:"readerCount"`
	TotalReaderCount int    `json:"totalReaderCount"`
}

type StreamList struct {
	Data []StreamInfo `json:"data,omitempty"`
}

func getCount(app string, stream string, result []byte) int {
	var ret int = 0
	var list StreamList
	err := json.Unmarshal(result, &list)
	if err != nil {
		Logger.Println("JsonToMapDemo err: ", err)
		return 0
	}
	fmt.Println("----------------------------------------------------------")
	for _, value := range list.Data {
		Logger.Println(value)
		if value.App == app && value.Stream == stream {

			if value.TotalReaderCount > 0 {
				Logger.Println("TotalReaderCount:", value.TotalReaderCount)
				return value.TotalReaderCount
			} else {
				Logger.Println("ReaderCount:", value.ReaderCount)
				ret += value.ReaderCount
			}
		}
	}
	fmt.Println("----------------------------------------------------------")
	return ret
}

type XueanHlsCheck struct {
	Ret     bool `json:"ret"`
	GetTime int  `json:"get_time"`
}

func GetXueanHlsCheckResponse(times int) string {
	// {
	// 	ret：true
	// 	get_time：1
	// }
	var res XueanHlsCheck
	res.Ret = true
	res.GetTime = times
	data, err := json.Marshal(res)
	if err != nil {
		log.Fatalf("JSON marshaling failed: %s", err)
		return ""
	} else {
		return string(data)
	}
}

func GetHlsCheckResponse(stream string) string {
	var req_url url.URL
	req_url.Scheme = ZlmScheme
	req_url.Host = ZlmIP + ":" + strconv.Itoa(ZlmPort)
	req_url.Path = "/index/api/getMediaList"
	var req_query url.Values = req_url.Query()
	req_query.Set("secret", ZlmSecret)
	req_query.Set("vhost", ZlmVhost)
	req_query.Set("app", "cam_remote")
	req_query.Set("stream", stream)
	req_url.RawQuery = req_query.Encode()
	req_url_str := req_url.String()
	Logger.Println(req_url_str)
	var res string = Get(req_url_str)
	getTime := getCount("cam_remote", stream, []byte(res))
	response := GetXueanHlsCheckResponse(getTime)
	return response
}

type XueanError struct {
	Ret     bool   `json:"ret"`
	ErrCode int    `json:"err_code"`
	ErrMsg  string `json:"err_msg"`
}

func GetErrorResponse(code int, msg string) string {
	// 返回错误的格式：
	// {
	// 	"err_code" : 400,
	// 	"err_msg" : "参数id错误",
	// 	"ret" : false,
	// }
	var res XueanError
	res.Ret = false
	res.ErrCode = code
	res.ErrMsg = msg
	data, err := json.Marshal(res)
	if err != nil {
		log.Fatalf("JSON marshaling failed: %s", err)
		return ""
	} else {
		return string(data)
	}
}

type SrsKbps struct {
	Recv30s int `json:"recv_30s"`
	Send30s int `json:"send_30s"`
}

type SrsStream struct {
	App     string  `json:"app"`
	Name    string  `json:"name"`
	Clients int     `json:"clients"`
	Kbps    SrsKbps `json:"kbps"`
}

type SrsApiResponse struct {
	Code    int         `json:"code"`
	Streams []SrsStream `json:"streams"`
}

func GetSrsStreamsResponse() string {
	// {
	// 	code: 0,
	// 	server: 100153,
	// 	streams: [   =======必须
	// 		{
	// 			id: 100180,
	// 			name: "test1",=======必须
	// 			vhost: 100154,
	// 			app: "test",=======必须
	// 			live_ms: 1625105372513,
	// 			clients: 1,=======必须
	// 			frames: 0,
	// 			send_bytes: 4189,
	// 			recv_bytes: 501937,
	// 			kbps: {=======必须
	// 				recv_30s: 0,=======必须  小于15会触发A9300断流逻辑
	// 				send_30s: 0
	// 			},
	// 			publish: {
	// 				active: true,
	// 				cid: 1686
	// 			},
	// 			video: {
	// 				codec: "H264",
	// 				profile: "Main",
	// 				level: "3.1"
	// 			},
	// 			audio: null
	// 		}
	// 	]
	// }

	var req_url url.URL
	req_url.Scheme = ZlmScheme
	req_url.Host = ZlmIP + ":" + strconv.Itoa(ZlmPort)
	req_url.Path = "/index/api/getMediaList"
	var req_query url.Values = req_url.Query()
	req_query.Set("secret", "035c73f7-bb6b-4889-a715-d9eb2d1925cc")
	req_query.Set("vhost", "__defaultVhost__")
	req_url.RawQuery = req_query.Encode()
	req_url_str := req_url.String()
	Logger.Println(req_url_str)
	var res string = Get(req_url_str)
	var list StreamList
	err := json.Unmarshal([]byte(res), &list)
	if err != nil {
		Logger.Println("JsonToMapDemo err: ", err)
		return ""
	}
	fmt.Println("----------------------------------------------------------")

	var resData SrsApiResponse
	resData.Code = 0
	resData.Streams = []SrsStream{}
	for _, value := range list.Data {
		Logger.Println(value)
		var resStream SrsStream
		resStream.App = value.App
		resStream.Name = value.Stream
		if value.TotalReaderCount > 0 {
			Logger.Println("TotalReaderCount:", value.TotalReaderCount)
			resStream.Clients = value.TotalReaderCount
		} else {
			Logger.Println("ReaderCount:", value.ReaderCount)
			resStream.Clients = value.ReaderCount
		}
		resStream.Kbps.Recv30s = value.BytesSpeed
		resStream.Kbps.Send30s = value.BytesSpeed

		var isExist bool = false
		for i := 0; i < len(resData.Streams); i++ {
			if resData.Streams[i].App == resStream.App && resData.Streams[i].Name == resStream.Name {
				isExist = true
				if value.TotalReaderCount > 0 {
					Logger.Println("TotalReaderCount:", value.TotalReaderCount)
					resData.Streams[i].Clients = value.TotalReaderCount
				} else {
					Logger.Println("ReaderCount:", value.ReaderCount)
					resData.Streams[i].Clients += value.ReaderCount
				}
				resData.Streams[i].Kbps.Recv30s += value.BytesSpeed
				resData.Streams[i].Kbps.Send30s += value.BytesSpeed
			}
		}
		if !isExist {
			resData.Streams = append(resData.Streams, resStream)
		}
	}
	fmt.Println("----------------------------------------------------------")
	data, err := json.Marshal(resData)
	if err != nil {
		log.Fatalf(" SON marshaling failed: %s", err)
		return ""
	} else {
		return string(data)
	}
}

func HandleHlsCheck() {
	http.HandleFunc("/hls_check.php", func(w http.ResponseWriter, r *http.Request) {
		Logger.Println(r)
		var request_url *url.URL = r.URL
		Logger.Println(request_url)
		var request_query url.Values = request_url.Query()
		Logger.Println(request_query)
		request_len := 0
		request_ids, ok := request_query["id"]
		if ok {
			request_len = len(request_ids)
		}
		Logger.Println(request_len)
		if ok && request_len == 1 {
			var cameraID = request_ids[0]
			Logger.Println(cameraID)
			data := GetHlsCheckResponse(cameraID)
			w.WriteHeader(200)
			fmt.Fprintf(w, data)
		} else {
			data := GetErrorResponse(400, "参数id错误")
			Logger.Printf("%s\n", data)
			w.WriteHeader(400)
			fmt.Fprintf(w, string(data))
		}
	})
}

func HandleSrsStreams() {
	http.HandleFunc("/api/v1/streams", func(w http.ResponseWriter, r *http.Request) {
		data := GetSrsStreamsResponse()
		w.WriteHeader(200)
		fmt.Fprintf(w, data)
	})
}

func initLogger() {
	Logger = logTofile("/tmp/hls_check.log", "[hls_check] ", log.Ldate|log.Ltime|log.Llongfile)
}

func main() {
	initLogger()
	initConfig()
	HandleHlsCheck()
	HandleSrsStreams()
	http.ListenAndServe("0.0.0.0:"+strconv.Itoa(ListenPort), nil)
	Logger.Println("Hello World!")
}
